package com.sduept.nwld.dataserver.manager.cim;

import com.sduept.cim.ledger.total.model.ProtectionDeviceCount;
import com.sduept.core.dao.SuperDAO;
import com.sduept.utils.DateUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

@Service
public class ProtectionDeviceCountPersistManager {
	public static final String sql = "SELECT #{unit} AS unitName,d.protected_type AS statisticTypeDesc ,d.standvoltage AS voltageLevel,COUNT(*) AS statisticCount FROM t_cim_protection_equipment d "
			+ "LEFT JOIN t_substation_ledger l ON d.sub_id = l.cimId "
			+ "GROUP BY #{unit},d.protected_type,d.standvoltage ";// having d.standvoltage in (0,35,110,220,500)";
	/**
	 * 联合查询t_cim_protection_equipment，t_substation_ledger两张表的基本信息根据sub_id = cimId
	 */
	public static final String equipmentSql ="SELECT d.sub_id ,d.protected_name,  #{unit} AS unitName,d.protected_type AS statisticTypeDesc ,d.standvoltage AS voltageLevel " 
	        + " FROM t_cim_protection_equipment d 	LEFT JOIN t_substation_ledger l ON d.sub_id = l.cimId  	 ";
	/**
	 * 从t_primary_equipment_ledger表里查出有哪些被保护设备
	 */
	public static final String ledgerSql = " select  d.sub_id,d.protected_name,   #{unit} AS unitName,  l.equipmentType AS statisticTypeDesc ,   d.standvoltage AS voltageLevel  FROM t_cim_protection_equipment d" 
	        + ", t_primary_equipment_ledger l where d.sub_id=l.cimId and d.protected_name=l.name";
	public static final byte dispatchType = 0;
	public static final byte ovelType = 1;
	// private final byte maintenceType = 2; 暂未使用
	public static final byte manuType = 3;
	
	
	@Autowired
	private SuperDAO dao;

	public void persistCountByTypeOverideManual(int type, boolean overideManual) {
		switch (type) {
		case 0:// 调管单位
			persistDispatchProtectCount(overideManual);
			break;
		case 1:// 检修单位
			persistOvelProtectCount(overideManual);
			break;
		case 3:// 生产厂家
			persistManuProtectCount(overideManual);
			break;
		}
	}
    
	/**
	 * 根据sql获得ProtectEquipmentAttribute集合
	 * @param sql
	 * @return
	 */
	private List<ProtectEquipmentAttribute> getProtectEquipmentAttributeList(String sql) {
		List<ProtectEquipmentAttribute> result = new ArrayList<>();
		List<?> lists =  dao.nativeQuery(sql);
		for (Object object : lists) {
			Object[] obj = (Object[]) object;
			ProtectEquipmentAttribute at = new ProtectEquipmentAttribute();
			at.setSubstation_id(obj[0]==null?"":obj[0].toString());;
			at.setProtected_name(obj[1]==null?"":obj[1].toString());
			at.setUnitName(obj[2]==null?"":obj[2].toString());
			at.setStatisticTypeDesc(obj[3]==null?"":obj[3].toString());
			at.setVoltageLevel(obj[4]==null?"":obj[4].toString());
			result.add(at);
		}
		return result;
	}

	/**
	 * 	按照调管单位统计保护信息 格式为 调管单位/保护类型/电压等级     数量
	 *  @param overideManual 是否覆盖人工填写的数据
	 */
	private void persistDispatchProtectCount(boolean overideManual) {
		String sql = getDispatchQuarySql(equipmentSql);
		//commonOperate(sql, dispatchType, overideManual);
		commonOperateEquipment(sql,dispatchType,overideManual);
	}

	

	/**
	 * 	按照运维单位统计保护信息 格式为 调管单位/保护类型/电压等级     数量
	 *  @param overideManual 是否覆盖人工填写的数据
	 */
	private void persistOvelProtectCount(boolean overideManual) {
		String sql = getOvelQuarySql(equipmentSql);
		//commonOperate(sql, ovelType, overideManual);
		commonOperateEquipment(sql, ovelType, overideManual);
	}

	/**
	 * 	按照生产厂家统计保护信息 格式为 调管单位/保护类型/电压等级     数量
	 *  @param overideManual 是否覆盖人工填写的数据
	 */
	private void persistManuProtectCount(boolean overideManual) {
		String sql = getManuQuarySql();
		commonOperate(sql, manuType, overideManual);
	}

	/**
	 * 	统计类型分类
	 * @author wk
	 *
	 */
	private enum StatisticType {
		xianlu {
			@Override
			String getName() {
				return "线路";
			}

			@Override
			byte getType() {
				return 0;
			}
		},
		muxian {
			@Override
			String getName() {
				return "母线";
			}

			@Override
			byte getType() {
				return 1;
			}
		},
		bianyaqi {
			@Override
			String getName() {
				return "变压器";
			}

			@Override
			byte getType() {
				return 2;
			}
		},
		fadianji {
			@Override
			String getName() {
				return "发电机";
			}

			@Override
			byte getType() {
				return 3;
			}
		},
		diankang {
			@Override
			String getName() {
				return "电抗器";
			}

			@Override
			byte getType() {
				return 4;
			}
		},
		chuanbu {
			@Override
			String getName() {
				return "串补";
			}

			@Override
			byte getType() {
				return 5;
			}
		},
		duanyinxian {
			@Override
			String getName() {
				return "短引线";
			}

			@Override
			byte getType() {
				return 6;
			}
		},
		duanluqi {
			@Override
			String getName() {
				return "断路器";
			}

			@Override
			byte getType() {
				return 7;
			}
		},
		wangluo {
			@Override
			String getName() {
				return "网络设备";
			}

			@Override
			byte getType() {
				return 9;
			}
		};
		abstract String getName();

		abstract byte getType();

		public static byte getTypeByName(String name) {
			for (StatisticType t : StatisticType.values()) {
				if (t.getName().equals(name)) {
					return t.getType();
				}
			}
			return -1;
		}
	}

	/**
	 * @param sql
	 * @param type
	 */
	private void commonOperate(String sql, byte type, boolean override) {
		List<ProtectionDeviceCount> sqlList = dao.nativeQuery(ProtectionDeviceCount.class, sql, null);
		List<ProtectionDeviceCount> list = transformer(sqlList, type);
		if (override) {
			persistProtectionDeviceCountOverride(type, list);
		} else {
			persistProtectionDeviceCountUnOverride(type, list);
		}
	}
     
	/**
	 * 处理设备信息
	 * @param sql
	 * @param type 单位类型
	 * @param overideManual 是否覆盖
	 */
	private void commonOperateEquipment(String sql, byte type, boolean overideManual) {
		List<ProtectEquipmentAttribute> attriButeList = getProtectEquipmentAttributeList(sql);
		List<ProtectionDeviceCount> list = getProtectionDeviceCounts(attriButeList, type);
		if (overideManual) {
			persistProtectionDeviceCountOverride(type, list);
		} else {
			persistProtectionDeviceCountUnOverride(type, list);
		}
		
	}
	
	

	/**
	 * 获取调管单位分类查询sql
	 * @param sql 
	 * @return
	 */
	private String getDispatchQuarySql(String sql) {
		return sql.replace("#{unit}", "dispatchUnit");
	}

	/**
	 * 获取检修单位分类查询sql
	 * @param sql 
	 * @return
	 */
	private String getOvelQuarySql(String sql) {
		return sql.replace("#{unit}", "primaryEquipmentScope");
	}

	/**
	 * 获取生产厂家分类查询sql
	 * @return
	 */
	private String getManuQuarySql() {
		return sql.replace("#{unit}", "dev_manufacturer");
	}

	/**
	 * 持久化保护动作数量,包括人工填写的一并覆盖
	 * @param list
	 */
	private void persistProtectionDeviceCountOverride(byte unitType, List<ProtectionDeviceCount> list) {
		Date start = getStartDate();
		Date end = getEndDate();
		dao.delete(ProtectionDeviceCount.class, "unitType=? AND statisticTime BETWEEN ? AND ?", unitType, start, end);
		for (ProtectionDeviceCount d : list) {
			dao.createOrUpdate(d, ProtectionDeviceCount.class);
		}
	}

	/**
	 * 久化保护动作数量,不覆盖人工填写的数据
	 * @param list
	 */
	private void persistProtectionDeviceCountUnOverride(byte unitType, List<ProtectionDeviceCount> list) {
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		Date statisticTime = list.get(0).getStatisticTime();
		Date start = getStartDate();
		Date end = getEndDate();
		// 清楚掉规定时间内自动统计的数据
		dao.delete(ProtectionDeviceCount.class, "unitType=? AND operateStatus=0 AND statisticTime BETWEEN ? AND ?",
				unitType, start, end);
		// 获取人工填报的数据，用于过滤传入的参数
		List<ProtectionDeviceCount> dblist = dao.findByCondition(ProtectionDeviceCount.class,
				"operateStatus=1 AND statisticTime BETWEEN ? AND ?", start, end);
		outer: for (ProtectionDeviceCount d : list) {
			for (ProtectionDeviceCount db : dblist) {
				if (db.getUnitName().equals(d.getUnitName()) && db.getVoltageLevel().equals(d.getVoltageLevel())
						&& db.getStatisticType().equals(d.getStatisticType())) {
					db.setStatisticTime(statisticTime);
					dao.createOrUpdate(db, ProtectionDeviceCount.class);
					continue outer;
				}
			}
			dao.createOrUpdate(d, ProtectionDeviceCount.class);
		}
	}

	/**
	 * 获得查询语句的开始时间
	 * @return
	 */
	private Date getStartDate() {
		Calendar instance = Calendar.getInstance();
		int year = instance.get(Calendar.YEAR);
		Date start = DateUtil.getDateByString(year + "-01-01", DateUtil.pattern_ymd);
		return start;
	}

	/**
	 * 获得查询语句的结束时间
	 * @return
	 */
	private Date getEndDate() {
		Calendar instance = Calendar.getInstance();
		int year = instance.get(Calendar.YEAR);
		Date start = DateUtil.getDateByString((year + 1) + "-01-01", DateUtil.pattern_ymd);
		return start;
	}

	/**
	 *	数据转换，将单位为空的进行统一统计，处理单位名称为null或者空串的情况
	 * 	@param list
	 * 	@return
	 */
	private List<ProtectionDeviceCount> transformer(List<ProtectionDeviceCount> list, byte unitType) {
		final Date statisticTime = new Date();
		List<ProtectionDeviceCount> result = new ArrayList<>();
		list.stream().map(p -> {
			if (StringUtils.isEmpty(p.getUnitName())) {
				p.setUnitName("未知");
			}
			p.setStatisticType(StatisticType.getTypeByName(p.getStatisticTypeDesc()));
			p.setStatisticTime(statisticTime);
			p.setUnitType(unitType);
			return p;
		}).collect(Collectors.groupingBy(p -> p.getUnitName() + "/" + p.getStatisticType() + "/" + p.getVoltageLevel()))
				.forEach((k, v) -> {
					Optional<ProtectionDeviceCount> reduce = v.stream().reduce((v1, v2) -> {
						v1.setStatisticCount(v1.getStatisticCount() + v2.getStatisticCount());
						return v1;
					});
					result.add(reduce.get());
				});
		return result;
	}
	
	/**
	 * 根据ProtectEquipmentAttribute集合和单位类型获得ProtectionDeviceCount集合
	 * @param attriButeList ProtectEquipmentAttribute集合
	 * @param unitType 单位类型
	 * @return
	 */
	private List<ProtectionDeviceCount> getProtectionDeviceCounts(List<ProtectEquipmentAttribute> attriButeList,byte unitType) {
		List<ProtectionDeviceCount> last = new ArrayList<>();
		String sql = getDispatchQuarySql(ledgerSql);
		List<ProtectEquipmentAttribute>  ledgerList = getProtectEquipmentAttributeList(sql) ;
		Map<String,List<ProtectEquipmentAttribute>> ledgerMap = groupByStationIdAndProtectedName(ledgerList);
		Map<String,List<ProtectEquipmentAttribute>>  equipmentMap = groupByStationIdAndProtectedName(attriButeList);
		List<ProtectEquipmentAttribute> result = new ArrayList<>();
		for(Entry<String, List<ProtectEquipmentAttribute>> map:equipmentMap.entrySet()) {
			String key = map.getKey();
			if(ledgerMap.keySet().contains(key)) {
				result.addAll(ledgerMap.get(key));
			}else {
				result.addAll(map.getValue());
			}
		}
		last = transformerMapToProtectionDeviceCounts(groupByUnitAndTypeAndVoltage(result),unitType);;
		return last;
	}
	
	
	
     /**
      * 将单位/类型/电压作为key的map 转换为ProtectionDeviceCount集合
      * @param map 
      * @param unitType 单位类型
      * @return
      */
	private List<ProtectionDeviceCount> transformerMapToProtectionDeviceCounts(Map<String, List<ProtectEquipmentAttribute>> map, byte unitType) {
		final Date statisticTime = new Date();
		 List<ProtectionDeviceCount> listCount = new ArrayList<>();
		for(Entry<String, List<ProtectEquipmentAttribute>>  atMap:map.entrySet()) {
			ProtectionDeviceCount count = new ProtectionDeviceCount();
			String[] str = atMap.getKey().split("/");
			String unitName = StringUtils.isEmpty(str[0])?"未知":str[0];
			String voltage = StringUtils.isEmpty(str[2])?"0":str[2];
			byte statisticType =  StatisticType.getTypeByName(str[1]);
			int voltageLevel = Integer.valueOf(voltage);
			count.setUnitName(unitName);
			count.setVoltageLevel(voltageLevel);
			count.setStatisticType(statisticType);
			count.setStatisticTime(statisticTime);
			count.setStatisticCount(Long.valueOf(atMap.getValue().size()));
			count.setUnitType(unitType);
			listCount.add(count);
		}
		return listCount;
	}
    /**
     * 将ProtectEquipmentAttribute集合 按照单位/类型/电压为key，ProtectEquipmentAttribute集合为value   组合成map
     * @param result
     * @return
     */
	private Map<String, List<ProtectEquipmentAttribute>> groupByUnitAndTypeAndVoltage(List<ProtectEquipmentAttribute> result) {
		Map<String,List<ProtectEquipmentAttribute>> map = result.stream().map(p -> {
			if(StringUtils.isEmpty(p.getUnitName())) {
				p.setUnitName("未知");
			}
			if(StringUtils.isEmpty(p.getStatisticTypeDesc())) {
				p.setStatisticTypeDesc("未知");
			}
			if(StringUtils.isEmpty(p.getVoltageLevel())) {
				p.setVoltageLevel("0");
			}
			return p;
			
		}).collect(Collectors.groupingBy(p -> p.getUnitName()+"/"+p.getStatisticTypeDesc()+"/"+p.getVoltageLevel()));
		return map;
	}
     
	/**
	 * 根據ProtectEquipmentAttribute集合 封装成stationId,protected_name为key,ProtectEquipmentAttribute集合为value的map
	 * @param list
	 * @return
	 */
	private Map<String, List<ProtectEquipmentAttribute>> groupByStationIdAndProtectedName(List<ProtectEquipmentAttribute> list) {
		Map<String,List<ProtectEquipmentAttribute>> map = new HashMap<>();
		for (ProtectEquipmentAttribute pro : list) {
			String stationId = pro.getSubstation_id()==null?"null":pro.getSubstation_id();
			String name = pro.getProtected_name() == null?"null":pro.getProtected_name();
			String key = stationId + ","+name;
			List<ProtectEquipmentAttribute> value = map.get(key);
			if(CollectionUtils.isEmpty(value)) {
				value = new ArrayList<>();
				map.put(key, value);
			}
			value.add(pro);
		}
		return map;
	}




	public  class ProtectEquipmentAttribute{
		
		private String substation_id;
		private String protected_name;
		private String unitName;
		private String statisticTypeDesc;
		private String voltageLevel;
		 
		 
		 
		public ProtectEquipmentAttribute() {
			// TODO Auto-generated constructor stub
		}
		public String getSubstation_id() {
			return substation_id;
		}
		public void setSubstation_id(String substation_id) {
			this.substation_id = substation_id;
		}
		public String getProtected_name() {
			return protected_name;
		}
		public void setProtected_name(String protected_name) {
			this.protected_name = protected_name;
		}
		public String getStatisticTypeDesc() {
			return statisticTypeDesc;
		}
		public void setStatisticTypeDesc(String statisticTypeDesc) {
			this.statisticTypeDesc = statisticTypeDesc;
		}
		public String getVoltageLevel() {
			return voltageLevel;
		}
		public void setVoltageLevel(String voltageLevel) {
			this.voltageLevel = voltageLevel;
		}
		public String getUnitName() {
			return unitName;
		}
		public void setUnitName(String unitName) {
			this.unitName = unitName;
		}
		
		
	}
	
	
}
